/**
 * 平滑图像
 * 1. 归一化滤波：blur()
 * 2. 高斯滤波：GaussianBlur()
 * 3. 中值滤波：medianBlur()
 * 4. 双边滤波（保护边缘）：bilateralFilter()
 *  - 其他滤波会模糊图片的边缘细节，对于高频细节的保护效果并不明显；双边滤波可以在去噪的同时，保护图像的边缘特性
 */

#include <iostream>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>

using namespace std;
using namespace cv;

/// Global Variables
int DELAY_CAPTION = 1500;
int DELAY_BLUR = 100;
int MAX_KERNEL_LENGTH = 31;

Mat src;
Mat dst;
char window_name[] = "Smoothing Demo";

/// Function headers
int display_caption(const char *caption);

int display_dst(int delay);

int main(int argc, char *argv[]) {
    namedWindow(window_name, WINDOW_AUTOSIZE);

    /// Load the source image
    const char *filename = argc >= 2 ? argv[1] : "lena.jpg";

    src = imread(samples::findFile(filename), IMREAD_COLOR);
    if (src.empty()) {
        printf(" Error opening image\n");
        printf(" Usage:\n %s [image_name-- default lena.jpg] \n", argv[0]);
        return EXIT_FAILURE;
    }

    if (display_caption("Original Image") != 0) {
        return 0;
    }

    dst = src.clone();
    if (display_dst(DELAY_CAPTION) != 0) {
        return 0;
    }

    /// Applying Homogeneous blur
    if (display_caption("Homogeneous Blur") != 0) {
        return 0;
    }

    //![blur]
    for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2) {
        blur(src, dst, Size(i, i), Point(-1, -1));
        if (display_dst(DELAY_BLUR) != 0) {
            return 0;
        }
    }
    //![blur]

    /// Applying Gaussian blur
    if (display_caption("Gaussian Blur") != 0) {
        return 0;
    }

    //![gaussianblur]
    for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2) {
        GaussianBlur(src, dst, Size(i, i), 0, 0);
        if (display_dst(DELAY_BLUR) != 0) {
            return 0;
        }
    }
    //![gaussianblur]

    /// Applying Median blur
    if (display_caption("Median Blur") != 0) {
        return 0;
    }

    //![medianblur]
    for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2) {
        medianBlur(src, dst, i);
        if (display_dst(DELAY_BLUR) != 0) {
            return 0;
        }
    }
    //![medianblur]

    /// Applying Bilateral Filter
    if (display_caption("Bilateral Blur") != 0) {
        return 0;
    }

    //![bilateralfilter]
    for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2) {
        bilateralFilter(src, dst, i, i * 2, i / 2);
        if (display_dst(DELAY_BLUR) != 0) {
            return 0;
        }
    }
    //![bilateralfilter]

    /// Done
    display_caption("Done!");

    return 0;
}

/**
 * @function display_caption
 */
int display_caption(const char *caption) {
    dst = Mat::zeros(src.size(), src.type());
    putText(dst, caption,
            Point(src.cols / 4, src.rows / 2),
            FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255));

    return display_dst(DELAY_CAPTION);
}

/**
 * @function display_dst
 */
int display_dst(int delay) {
    imshow(window_name, dst);
    int c = waitKey(delay);
    if (c >= 0) { return -1; }
    return 0;
}
